package algorithm;

import java.util.List;
import java.util.Vector;


import util.VectorMath;

/**
 * A region represents one area broken up by this cluster algorithm.
 * 
 * @author Dan Avila
 * 
 */
public class Region_Original extends Region
{
	private RADDACL_Cluster parent;
	private List<Integer> inputIndexes;
	private DistanceTable_Original distanceTable;
	
	private Double pthreshold;
	private Vector<Double> pcentroid;
	/**
	 * The constructor for the first Region, which represents all data.
	 * 
	 * @param parent
	 *            - the parent cluster
	 * @param pointIndexes
	 *            - list of indexes that point to the inputs located in the
	 *            parent cluster
	 */
	public Region_Original(RADDACL_Cluster parent, List<Integer> inputIndexes) {
		this.inputIndexes = inputIndexes;
		this.parent = parent;
		
		this.distanceTable = new DistanceTable_Original(parent, this);
		this.distanceTable.generateDistanceTable();
	}
	/**
	 * The constructor for any Region besides the first.
	 * 
	 * @param parent
	 *            - the parent cluster
	 * @param pointIndexes
	 *            - list of indexes that point to the inputs located in the
	 *            parent cluster
	 */
	public Region_Original(RADDACL_Cluster parent, List<Integer> inputIndexes, 
			Double pthreshold, Vector<Double> pcentroid) 
	{
		this.inputIndexes = inputIndexes;
		this.parent = parent;
		this.pthreshold = pthreshold;
		this.pcentroid = pcentroid;

		this.distanceTable = new DistanceTable_Original(parent, this);
		this.distanceTable.generateDistanceTable();
	}
	@Override
	public boolean isPreCluster() {
		try {
			if(inputIndexes.size()== 1)
			{
				return true;
			}
			else
			{
				return StrictMath.abs(this.distanceTable.getMean() - this.distanceTable.getMedian()) <= this.distanceTable.getStandardDeviation();
			}
		} catch (NullPointerException e) {
			return false;
		}
	}
	/**
	 * Calculates the distance between the two furthest points in these two regions.
	 * 
	 * @param region - the region to compare with this region.
	 * 
	 * @return the distance in the form of a double
	 */
	public double calculateCompleteLinkDistance(Region region)
	{
		double maxDistance = 0.0;
		
		for(Integer index: inputIndexes)
		{
			for(Integer index2: region.getIndexes())
			{
				double distance = VectorMath.euclidianDistance(
						parent.inputs.get(index), 
						parent.inputs.get(index2)
						);
				
				if(maxDistance < distance)
				{
					maxDistance = distance;
				}
			}
		}
		
		return maxDistance;
	}
	@Override
	public Vector<Double> getCentroid() 
	{
		return this.distanceTable.getCentroid();
	}

	public Vector<Double> getPCentroid()
	{
		return this.pcentroid;
	}
	public double getMean() 
	{
		return this.distanceTable.getMean();
	}

	public double getStandardDeviation() 
	{
		return this.distanceTable.getStandardDeviation();
	}
	@Override
	public double getThreshold() 
	{
		return 0.0;
	}
	@Override
	public List<Integer> getIndexes() 
	{
		return this.inputIndexes;
	}
	@Override
	public void mergeRegion(Region r) 
	{
		this.inputIndexes.addAll(r.getIndexes());
	}

	public void mergeRegionAndRecalc(Region region) 
	{
		this.mergeRegion(region);
	}
}
